package view;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.nio.file.WatchEvent.Kind;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;

import javax.swing.BorderFactory;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.Timer;
import javax.swing.border.TitledBorder;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreePath;

import model.Filter;
import model.EmailImp;

import resources.ResourceProvider;

/**
 *  This is class to display JTree for email folder hierarchy.
 */
public class EMailFolderHierarchyTree  extends JTree
{
    
	private static final long serialVersionUID = 2623052575187257101L;
	
	private JPopupMenu treePopup;
		
	private ActionListener popUpHandler;
	
    private Point locationOfClick;

    private EmailFolderNode mailbox;
    
    private EmailFolderNode inbox;
    
    private EmailFolderNode draft;
    
    private EmailFolderNode outbox;
    
    private EmailFolderNode sent;
    
    private EmailFolderNode thrash;
    
    private EmailApplicationView emailApplicationView;
    
    /**
     * Constructor for class EmailFolderHierarchy tree having attributes email application view and mail.
     * @param emailApplicationView email application view reference
     * @param emailNode mail node
     */
	public EMailFolderHierarchyTree(EmailApplicationView emailApplicationView, EmailFolderNode emailNode) 
    {
       super(emailNode);
       this.mailbox = new EmailFolderNode(ResourceProvider.MAILBOX);
       this.emailApplicationView = emailApplicationView;
       this.mailbox = emailNode;
       String user = this.emailApplicationView.getController().getUser();
       this.inbox = new EmailFolderNode(ResourceProvider.INBOX);
       this.inbox.setPersistenceFilePath(ResourceProvider.getRootFolderPath(ResourceProvider.INBOX, user));
       
       this.draft = new EmailFolderNode(ResourceProvider.DRAFT);
       this.draft.setPersistenceFilePath(ResourceProvider.getRootFolderPath(ResourceProvider.DRAFT, user));

       this.outbox = new EmailFolderNode(ResourceProvider.OUTBOX);
       this.outbox.setPersistenceFilePath(ResourceProvider.getRootFolderPath(ResourceProvider.OUTBOX, user));

       this.sent = new EmailFolderNode(ResourceProvider.SENT);
       this.sent.setPersistenceFilePath(ResourceProvider.getRootFolderPath(ResourceProvider.SENT, user));

       this.thrash = new EmailFolderNode(ResourceProvider.TRASH);
       this.thrash.setPersistenceFilePath(ResourceProvider.getRootFolderPath(ResourceProvider.TRASH, user));

       
       this.mailbox.add(this.inbox);
       this.mailbox.add(this.draft);
       this.mailbox.add(this.outbox);
       this.mailbox.add(this.sent);
       this.mailbox.add(this.thrash);
       
       
       this.treePopup = new JPopupMenu();
       this.treePopup.setInvoker(this);
       
       this.popUpHandler = new ActionListener() 
       {
		
		/*
		 * (non-Javadoc)
		 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
		 */
		public void actionPerformed(ActionEvent e) 
	    {
	        String option = e.getActionCommand();
	        TreePath path  = EMailFolderHierarchyTree.this.getPathForLocation(locationOfClick.x, locationOfClick.y);
	        	        
	        if(option.equalsIgnoreCase(ResourceProvider.ADD_FOLDER)) 
	        {
	        	Object treeObject = path.getLastPathComponent();
	        	if(treeObject instanceof EmailFolderNodeImp)
	        	{		        		
	        			String newFolderName = JOptionPane.showInputDialog(EMailFolderHierarchyTree.this.getParent().getParent().getParent().getParent(), 
                                "Enter the New Folder name", 
                                "Create New Folder", 
                                JOptionPane.QUESTION_MESSAGE);
	        			if(newFolderName == null)
	        			{
	        			    return;
	        			}
	        			
	        			if(newFolderName.isEmpty())
	        			{	
	              	          final JPanel panel = new JPanel();
	            	          JOptionPane.showMessageDialog(panel, "Folder name should not be empty!", "Warning",
	            	          JOptionPane.WARNING_MESSAGE);
	        			}
	        			else if(newFolderName.matches(".*?[\\p{Punct}&&[^_]].*"))
	        			{
	              	          final JPanel panel = new JPanel();
	            	          JOptionPane.showMessageDialog(panel, "Folder name can't contain any of following characters:!@#$%^&*", "Warning",
	            	          JOptionPane.WARNING_MESSAGE);
	        			}
	        			else
	        			{
	        				EmailFolderNode treeNode = (EmailFolderNode) treeObject;
		        			Boolean isExist = EMailFolderHierarchyTree.this.checkIfFolderExist(treeNode, newFolderName);
		        			if(isExist)
		        				{
		        					JOptionPane.showMessageDialog(EMailFolderHierarchyTree.this.getParent().getParent().getParent().getParent(), "Sorry, folder name already exists!", "Warning",
		        					        JOptionPane.WARNING_MESSAGE);
		        				}
		        			else
		        				{   

		                                String filePath = treeNode.getPersistenceFilePath() + ResourceProvider.getFilePathSeperator() + newFolderName;
	    
		        				        //persist folder	        				        
		        				        EMailFolderHierarchyTree.this.emailApplicationView.getController().requestCreateFile(filePath);
		        				        
		                                //display node in the tree hierarchy
		                                EmailFolderNode newFolder = new EmailFolderNode(newFolderName);
		                                newFolder.setPersistenceFilePath(filePath);
		                                
		                                treeNode.add(newFolder);
		                                DefaultTreeModel model = (DefaultTreeModel) EMailFolderHierarchyTree.this.getModel();
		                                model.reload();
		                                EMailFolderHierarchyTree.this.setSelectionPath(path);
		                                EMailFolderHierarchyTree.this.setExpandsSelectedPaths(true);
		        				}
		        		   }
	        			
	        		}
	        }
	        else if(option.equalsIgnoreCase(ResourceProvider.DELETE_FOLDER))
	        {
	        	 int deleteFolder = JOptionPane.showConfirmDialog(EMailFolderHierarchyTree.this.getParent().getParent().getParent().getParent(), "Are you sure to delete this folder?", "Warning",
					        JOptionPane.YES_NO_OPTION);
	
                        if(deleteFolder == JOptionPane.OK_OPTION)
                        {
                            EmailFolderNode selectedNode = (EmailFolderNode) EMailFolderHierarchyTree.this.getLastSelectedPathComponent();  
                            String selectNodePath = selectedNode.getPersistenceFilePath();
                            EMailFolderHierarchyTree.this.emailApplicationView.getController().requestDeleteFiles(selectNodePath);
                            if (selectedNode != null && selectedNode.getParent() != null)  
                            {  
                            	DefaultTreeModel model = (DefaultTreeModel) EMailFolderHierarchyTree.this.getModel();
                                model.removeNodeFromParent(selectedNode);  
                            }             	 
                        }
	        }
	        else if(option.equalsIgnoreCase(ResourceProvider.OPEN))
	        {
	            EmailFolderNode selectedNode = (EmailFolderNode) EMailFolderHierarchyTree.this.getLastSelectedPathComponent();  
                String filePath = selectedNode.getPersistenceFilePath();
	            EMailFolderHierarchyTree.this.emailApplicationView.getMailDisplayArea().displayEmails(filePath);
	        }
	        else if(option.equalsIgnoreCase(ResourceProvider.MOVE_TO))
            {
                
	            DefaultMutableTreeNode sourceNodeToMove = (DefaultMutableTreeNode) EMailFolderHierarchyTree.this.getLastSelectedPathComponent();
                
	            EmailFolderNodeImp inbox = null;
	            
	            int mailboxChildCount = EMailFolderHierarchyTree.this.mailbox.getChildCount();
	            for(int n=0;n<mailboxChildCount;n++)
	            {
	                EmailFolderNodeImp folderNode = (EmailFolderNodeImp) EMailFolderHierarchyTree.this.mailbox.getChildAt(n);
	                if(folderNode.getFolderName().equals(ResourceProvider.INBOX))
	                {
	                    inbox = folderNode;
	                }
	            }                
                
                EmailFolderNode optionInbox = new EmailFolderNode(ResourceProvider.INBOX);
                JTree tree = new JTree(optionInbox);
                
                Map<EmailFolderNodeImp,EmailFolderNodeImp> referenceNodeMap = new LinkedHashMap<EmailFolderNodeImp,EmailFolderNodeImp>();
                referenceNodeMap.put(optionInbox, inbox);
               
                EMailFolderHierarchyTree.this.iternateChildrenNodes(inbox,optionInbox,referenceNodeMap,sourceNodeToMove);
                                    
               JPanel panel = new JPanel();
               panel.setLayout(new BorderLayout(10, 10));
               TitledBorder title = BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.black), "");
               panel.setBorder(title);
               panel.add(new JScrollPane(tree));
               for (int j = 0; j < tree.getRowCount(); j++) 
               {
                   tree.expandRow(j);
               }
               
               int optionSelected = JOptionPane.showConfirmDialog(null,
                    panel,
                    "Move To",
                    JOptionPane.OK_CANCEL_OPTION,
                    JOptionPane.PLAIN_MESSAGE);
               
               if(optionSelected == JOptionPane.OK_OPTION)
               {
                   EmailFolderNodeImp selectedNode = (EmailFolderNodeImp)tree.getLastSelectedPathComponent();
                   DefaultMutableTreeNode destinationNodeToMove = (DefaultMutableTreeNode) referenceNodeMap.get(selectedNode);
                   
                   if(destinationNodeToMove != null)
                   {
                       String originalFileNamePath = ((EmailFolderNode) sourceNodeToMove).getPersistenceFilePath();
                       String moveToFileNamePath = ((EmailFolderNodeImp)destinationNodeToMove).getPersistenceFilePath() + ResourceProvider.getFilePathSeperator() + ((EmailFolderNodeImp)sourceNodeToMove).getFolderName() ;
                                              
                       //persist folder
                       EMailFolderHierarchyTree.this.emailApplicationView.getController().requestMoveToFile(originalFileNamePath, moveToFileNamePath);

                       // move to the destination node
                       destinationNodeToMove.add(sourceNodeToMove);
                       
                       // update the new persistence file path
                       ((EmailFolderNode)sourceNodeToMove).setPersistenceFilePath(moveToFileNamePath);
                       
                       EMailFolderHierarchyTree.this.setSelectionPath(path);
                       EMailFolderHierarchyTree.this.setExpandsSelectedPaths(true);
                       DefaultTreeModel model = (DefaultTreeModel) EMailFolderHierarchyTree.this.getModel();
                       model.reload();
                   }
               }
               
               referenceNodeMap.clear();
               referenceNodeMap = null;
            }
	    }
	};
        
	MouseListener mouseActionListener = new MouseAdapter() {
           /**
         * @param e
         */
        private void check(MouseEvent e) 
           {
           	// Mouse right click detection
           	if(e.getButton() == MouseEvent.BUTTON3)
           	{
           		int row = EMailFolderHierarchyTree.this.getRowForLocation(e.getX(), e.getY());
           		if (row == -1)
           		{
           			return;
           		}
                   
                if (e.isPopupTrigger())
                {
                	
                   TreePath path  = EMailFolderHierarchyTree.this.getPathForLocation(e.getX(), e.getY());
         	       Object treeObject = path.getLastPathComponent();
         	       EmailFolderNodeImp folderNode = (EmailFolderNodeImp) treeObject;
	        	   
	        	   EMailFolderHierarchyTree.this.loadPopMenuOptions(folderNode);
         	       
                	
                   EMailFolderHierarchyTree.this.setSelectionRow(row);
                   EMailFolderHierarchyTree.this.treePopup.show((Component) e.getSource(), e.getX(), e.getY());
                   EMailFolderHierarchyTree.this.locationOfClick = e.getPoint();
                }
           	}
           }
    
          
        public void mousePressed(MouseEvent e)  
           { 
           	check(e);
           }
           public void mouseReleased(MouseEvent e) 
           { 
           	check(e);
           }
           public void mouseClicked(MouseEvent e)  
           {
               // Mouse right click detection
               if((e.getButton() == MouseEvent.BUTTON1) && (e.getClickCount() == 2))
               {
                   int row = EMailFolderHierarchyTree.this.getRowForLocation(e.getX(), e.getY());
                   if (row == -1)
                   {
                       return;
                   }
                   
                   TreePath path  = EMailFolderHierarchyTree.this.getPathForLocation(e.getX(), e.getY());
                   Object treeObject = path.getLastPathComponent();
                   EmailFolderNodeImp folderNode = (EmailFolderNodeImp) treeObject;
                   if(!ResourceProvider.MAILBOX.equals(folderNode.getFolderName()))
                   {
                       EMailFolderHierarchyTree.this.emailApplicationView.displayInMailDisplayArea(folderNode.getPersistenceFilePath());
                       EMailFolderHierarchyTree.this.emailApplicationView.displayInButtonArea(folderNode.getPersistenceFilePath());
                   }
      
               }
               else
               {
                   check(e);
               }
           }
       };
       
       this.addMouseListener(mouseActionListener);
       
   	KeyListener keyEventlistener=new KeyListener() 
   	{
   		
   		public void keyTyped(KeyEvent e)
   		{
   			  			
   		}
   		public void keyReleased(KeyEvent e) 
   		{
   			
   		}
		
		public void keyPressed(KeyEvent e) 
		{
  			//hot keys to open folder
				DefaultTreeModel model = (DefaultTreeModel) EMailFolderHierarchyTree.this.getModel();

   			if ((e.getKeyCode() == KeyEvent.VK_O) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) 
   			{
                               
                 EmailFolderNodeImp selectedNode= (EmailFolderNodeImp) EMailFolderHierarchyTree.this.getLastSelectedPathComponent();
				 if(!((EmailFolderNodeImp)selectedNode).getFolderName().equals(ResourceProvider.MAILBOX))
				 {
					 EMailFolderHierarchyTree.this.emailApplicationView.displayInMailDisplayArea(selectedNode.getPersistenceFilePath());
				 }
			}
   			
   			// hot keys to delete folder
   			
   			else if ((e.getKeyCode() == KeyEvent.VK_DELETE) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) 
   			{                
                EmailFolderNodeImp selectedNode= (EmailFolderNodeImp) EMailFolderHierarchyTree.this.getLastSelectedPathComponent();
                if(selectedNode == null)
                {
                	return;
                }
                
                String folderName = selectedNode.getFolderName();
                 
                if(folderName.equals(ResourceProvider.INBOX) || folderName.equals(ResourceProvider.DRAFT) || folderName.equals(ResourceProvider.SENT) 
              			  || folderName.equals(ResourceProvider.TRASH) || folderName.equals(ResourceProvider.OUTBOX)|| folderName.equals(ResourceProvider.MAILBOX))
				 {
                	 JOptionPane.showMessageDialog(getParent(), "Root folder cannot be deleted!");
				 }
                 else
                 {
                	 int deleteFolder = JOptionPane.showConfirmDialog(EMailFolderHierarchyTree.this.getParent().getParent().getParent().getParent(), "Are you sure to delete this folder?", "Warning",
   		 					JOptionPane.YES_NO_OPTION);
                	 if(deleteFolder == JOptionPane.OK_OPTION)
                	 {
                         String filePath = selectedNode.getPersistenceFilePath();
                         
                         // move to Thrash
                         String user = EMailFolderHierarchyTree.this.emailApplicationView.getController().getUser();
                         String destinationPath = ResourceProvider.getRootFolderPath(ResourceProvider.TRASH,user) + ResourceProvider.getFilePathSeperator() + selectedNode.getFolderName();
                         EMailFolderHierarchyTree.this.emailApplicationView.getController().requestMoveToFile(filePath,destinationPath); 

                		 model.removeNodeFromParent((MutableTreeNode) selectedNode);	
                 }
               }
             }
   			
            // hot keys to add folder	
   			
   			else if ((e.getKeyCode() == KeyEvent.VK_K) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) 
   					
   			{        		
                EmailFolderNodeImp selectedNode= (EmailFolderNodeImp) EMailFolderHierarchyTree.this.getLastSelectedPathComponent();
        		
   				if((selectedNode instanceof EmailFolderNodeImp) && selectedNode.getPersistenceFilePath().contains(ResourceProvider.INBOX))
   					{		        		
   					 String newFolderName = JOptionPane.showInputDialog(EMailFolderHierarchyTree.this.getParent().getParent().getParent().getParent(), 
   					"Enter the New Folder name", 
   					"Create New Folder", 
   					JOptionPane.QUESTION_MESSAGE);
   					 
   					 if(newFolderName == null)
   					 {
   					     return;
   					 }
   					 
   					 if(newFolderName.isEmpty())
                       {   
                             final JPanel panel = new JPanel();
                             JOptionPane.showMessageDialog(panel, "Folder name should not be empty!", "Warning",
                             JOptionPane.WARNING_MESSAGE);
                       }
                       else if(newFolderName.matches(".*?[\\p{Punct}&&[^_]].*"))
                       {
                             final JPanel panel = new JPanel();
                             JOptionPane.showMessageDialog(panel,"Special characters not allowed","Warning",JOptionPane.WARNING_MESSAGE);
                       }
                      else
                       {
                           EmailFolderNode treeNode = (EmailFolderNode) selectedNode;
                           Boolean isExist = EMailFolderHierarchyTree.this.checkIfFolderExist(treeNode, newFolderName);
                          if(isExist)
                               {
                                   JOptionPane.showMessageDialog(EMailFolderHierarchyTree.this.getParent().getParent().getParent().getParent(), "Sorry, folder name already exists!", "Warning",
                                          JOptionPane.WARNING_MESSAGE);
                               }
                           else
                               {   

                                       String filePath = treeNode.getPersistenceFilePath() + ResourceProvider.getFilePathSeperator() + newFolderName;
                                       EMailFolderHierarchyTree.this.emailApplicationView.getController().requestCreateFile(filePath);
                                       
                                      //display node in the tree hierarchy
                                      EmailFolderNode newFolder = new EmailFolderNode(newFolderName);
                                       newFolder.setPersistenceFilePath(filePath);                                       
                                      treeNode.add(newFolder);
                                       DefaultTreeModel model1 = (DefaultTreeModel) EMailFolderHierarchyTree.this.getModel();
                                       model1.reload();
                                       EMailFolderHierarchyTree.this.setExpandsSelectedPaths(true);
                               }
                          }
		}
   		
   			}}
   	};
   			

   	       this.addKeyListener(keyEventlistener);

    }


	/**
	 * load option for pop menu
	 * @param folderNode the folder node
	 */
	public void loadPopMenuOptions(EmailFolderNodeImp folderNode)
	{
       this.resetPopUpMenu();
       
       String folderName = folderNode.getFolderName();
		
	   if(ResourceProvider.INBOX.equalsIgnoreCase(folderName))
       {
		   this.addPopUpMenuForInbox();
       }
       else if(ResourceProvider.OUTBOX.equalsIgnoreCase(folderName))
       {
    	   this.addPopUpMenuForOutbox();
       }
       else if(ResourceProvider.SENT.equalsIgnoreCase(folderName))
       {
    	   this.addPopUpMenuForSent();
       }
       else if(ResourceProvider.DRAFT.equalsIgnoreCase(folderName))
       {
    	   this.addPopUpMenuForDraft();
       }
       else if(ResourceProvider.TRASH.equalsIgnoreCase(folderName))
       {
    	   this.addPopUpMenuForTrash();
       }
       else if(ResourceProvider.MAILBOX.equalsIgnoreCase(folderName))
       {
    	   //do nothing
    	   return;
       }
       else
       {

          // it is a folder
          this.addPopUpMenuForFolders();
       }
	}
	
	


	/**
	 * add pop up menu for the folders
	 */
	public void addPopUpMenuForFolders() 
	{
		this.treePopup.add(this.getMenuItem(ResourceProvider.ADD_FOLDER, this.popUpHandler));
	    this.treePopup.add(this.getMenuItem(ResourceProvider.OPEN, this.popUpHandler));
	    this.treePopup.add(this.getMenuItem(ResourceProvider.DELETE_FOLDER,this.popUpHandler));
	    this.treePopup.add(this.getMenuItem(ResourceProvider.MOVE_TO,this.popUpHandler));
	    
	}

	/**
	 * check if folder exist in the given tree node with the given name
	 * @param treeNode the tree node
	 * @param newFolderName the new folder name
	 * @return returns a boolean signaling the existence of a folder node
	 */
	public Boolean checkIfFolderExist(EmailFolderNode treeNode, String newFolderName) 
	{
		int numberOfChildren = treeNode.getChildCount();
		
		for(int i = 0; i < numberOfChildren; i++)
		{
			EmailFolderNode childNode = (EmailFolderNode) treeNode.getChildAt(i);
			String childFolderName = childNode.getFolderName();
			if(newFolderName.equalsIgnoreCase(childFolderName))
			{
				return true;
			}
		}
		
		return false;
	}

	/**
	 * add popup menu for the Inbox root folder
	 */
	public void addPopUpMenuForInbox()
	{
		this.treePopup.add(this.getMenuItem(ResourceProvider.ADD_FOLDER, this.popUpHandler));
	    this.treePopup.add(this.getMenuItem(ResourceProvider.OPEN, this.popUpHandler));
	}
	
	/**
	 * add popup menu for Outbox
	 */
	public void addPopUpMenuForOutbox()
	{
		this.treePopup.add(this.getMenuItem(ResourceProvider.OPEN, this.popUpHandler));
	}

	/**
	 * add popup menu for SENT root folder
	 */
	public void addPopUpMenuForSent()
	{
	    this.treePopup.add(this.getMenuItem(ResourceProvider.OPEN, this.popUpHandler));
	}
	
	/**
	 * add popup menu for the THRASH root folder
	 */
	public void addPopUpMenuForTrash()
	{
	    this.treePopup.add(this.getMenuItem(ResourceProvider.OPEN, this.popUpHandler));
	}
	
	/**
	 * add popup menu for the DRAFT root folder
	 */
	public void addPopUpMenuForDraft()
	{
	    this.treePopup.add(this.getMenuItem(ResourceProvider.OPEN, this.popUpHandler));
	}
	
	/**
	 * reset the pop up menu
	 */
	public void resetPopUpMenu()
	{
		this.treePopup.removeAll();
	}
	
	/**
	 * get menu items for given option
	 * @param option the option
	 * @param handler the handler
	 * @return returns a menu item object. 
	 */
	private JMenuItem getMenuItem(String option, ActionListener handler) 
	  {
	        JMenuItem item = new JMenuItem(option);
	        
	        //set action command
	        item.setActionCommand(option.toUpperCase());
	        
	        //add action listener
	        item.addActionListener(handler);
	        
	        return item;
	  }
	  
	/**
	 * iterate child nodes for given nodes
	 * @param folderHierarchyNode the folder node
	 * @param displayNodeToMove the display node to move
	 * @param referenceNodeMap the reference node
	 * @param sourceNodeToMove the source node to move
	 */
	private void iternateChildrenNodes(EmailFolderNodeImp folderHierarchyNode, EmailFolderNode displayNodeToMove, Map<EmailFolderNodeImp, EmailFolderNodeImp> referenceNodeMap, DefaultMutableTreeNode sourceNodeToMove) 
      {
	      List<EmailFolderNodeImp> folderNodeList = folderHierarchyNode.getFolders();
          for(EmailFolderNodeImp folder : folderNodeList)
          {
             if(!folder.equals(sourceNodeToMove))
             {
                 EmailFolderNode folderNode = new EmailFolderNode(folder.getFolderName());
                 displayNodeToMove.add(folderNode);
                 referenceNodeMap.put(folderNode, folder);
                 this.iternateChildrenNodes(folder, folderNode, referenceNodeMap,sourceNodeToMove);  
             }
          }
      }
	
	/**
     * load persistence folders
     */
    public void loadPersistenceFolders()
    {        
        this.inbox.loadPersistenceFolders();
        this.listenForChanges(inbox);
   
        this.draft.loadPersistenceFolders();
        this.listenForChanges(draft);

        this.outbox.loadPersistenceFolders();
        this.listenForChanges(outbox);

        this.sent.loadPersistenceFolders();
        this.listenForChanges(sent);

        this.thrash.loadPersistenceFolders();
        this.listenForChanges(thrash);
    }    
    
    /**
     * listen to directory changes
     * @param folderNode email folder node
     */
    private void listenForChanges(final EmailFolderNode folderNode) 
    {
        //start in a new thread
        Thread newthread = new Thread(new Runnable() 
        {
            /*
             * (non-Javadoc)
             * @see java.lang.Runnable#run()
             */
            public void run() 
            {
                try 
                {
                    File folder = new File(folderNode.getPersistenceFilePath());
                    Path path = folder.toPath();
                    if (folder.isDirectory()) 
                    {
                        WatchService ws = path.getFileSystem().newWatchService();
                        path.register(ws, StandardWatchEventKinds.ENTRY_CREATE);
                        WatchKey watch = null;
                        while (true)
                        {                            
                                watch = ws.take();
                                List<WatchEvent<?>> events = watch.pollEvents();
                                watch.reset();
                                for (WatchEvent<?> event : events) 
                                {
                                    final Kind<Path> kind = (Kind<Path>) event.kind();
                                    final Path context = (Path) event.context();
                                    
                                    
                                    Timer timer = new Timer(100, new ActionListener()
                                    {
                                        @Override
                                        public void actionPerformed(ActionEvent e)
                                        {
                                        	EMailFolderHierarchyTree.this.reLoadViews(folderNode);
                                            
                                            if (kind.equals(StandardWatchEventKinds.ENTRY_CREATE))
                                            {
                                                String user = EMailFolderHierarchyTree.this.emailApplicationView.getController().getUser();
                                                if(context.getFileName().toString().endsWith(".json") && folderNode.getPersistenceFilePath().contains(ResourceProvider.getRootFolderPath(ResourceProvider.INBOX, user)))
                                                {
                                                    String emailFilePath = ResourceProvider.getRootFolderPath(ResourceProvider.INBOX, user) + ResourceProvider.getFilePathSeperator() + context.getFileName();
                                                    EMailFolderHierarchyTree.this.notifyNewEmailReceived(emailFilePath);            	
                                                }
                                                else if(context.getFileName().toString().endsWith(".json") && folderNode.getPersistenceFilePath().contains(ResourceProvider.getRootFolderPath(ResourceProvider.OUTBOX, user)))
                                                {
                                                    String emailFilePath = ResourceProvider.getRootFolderPath(ResourceProvider.OUTBOX, user) + ResourceProvider.getFilePathSeperator() + context.getFileName();
                                                    EMailFolderHierarchyTree.this.notifyOutboxEmailReceived(emailFilePath);                
                                                }
                                            }              }
                                    });
                                    timer.setRepeats(false);
                                    timer.start();	
                             
                                } 
                        }
                    } 
                } 
                catch (InterruptedException ex) 
                {
                    ex.printStackTrace();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }    
            }          
        });     
        newthread.start();
    }

    /**
     * notify email received in Outbox
     * @param emailFilePath the email file path
     */
    public void notifyOutboxEmailReceived(final String emailFilePath)
    {
    	 emailApplicationView.getController().emailReceivedToOutbox(emailFilePath);
    }


    /**
     * reload views
     * @param folderNode the folder node
     */
    public void reLoadViews(EmailFolderNode folderNode)
    {  
        EmailFolderNode selectedNode = (EmailFolderNode) EMailFolderHierarchyTree.this.getLastSelectedPathComponent();  
        if(selectedNode != null)
        {
            String filePath = selectedNode.getPersistenceFilePath();
            if(folderNode.getPersistenceFilePath().equals(filePath))
            {
                EMailFolderHierarchyTree.this.emailApplicationView.getMailDisplayArea().displayEmails(filePath);
            } 
        }        
    }


    /**
     * notify new email received call back
     * @param emailFilePath the email file path
     */
    public void notifyNewEmailReceived(final String emailFilePath)
    {   
        this.applyFilterforEmail(emailFilePath);  
    }

    /**
     * apply filter for the new mail received
     * @param fileName the email file path
     */
    public void applyFilterforEmail(String emailFilePath)
    {
       TreeSet<Filter> activeFilters = new TreeSet<Filter >( );
       
       String user = this.emailApplicationView.getController().getUser();
       String filterPath = ResourceProvider.getRootFolderPath(ResourceProvider.FILTERS, user);
       

       List<Filter> filterList = this.emailApplicationView.getController().requestFiltersFromPersistence(filterPath);        
       
       for(Filter filR : filterList)
       {
           if(filR.isEnabled())
           {
               activeFilters.add(filR);
           }   
       }
       
       
       for(Filter filT : activeFilters)
   	   {
          boolean searchFound = filT.isSearchFound(emailFilePath);
          if(searchFound)
          {
              EmailImp email = this.emailApplicationView.getController().requestEmailFromJson(emailFilePath);
              this.emailApplicationView.getController().requestFileDelete(emailFilePath);
              this.emailApplicationView.getController().requestPersitEmail(email, filT.getDestination());
        	  break;
          }
           
       }
    }
}
